package com.shop.cereshop.app.tencent.im.callback;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.shop.cereshop.commons.tencent.im.model.callback.request.*;
import com.shop.cereshop.commons.tencent.im.model.callback.response.CallbackResponse;
import com.shop.cereshop.commons.tencent.im.utils.JsonUtils;
import static com.shop.cereshop.commons.tencent.im.constant.CallbackCommand.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;



/**
 * @description: TimCallbackHandler工厂，自动注册所有 Handler
 * @author zdd
 * @date 2025/9/11 11:55
 * @version 1.0
 */
@Slf4j
@Component
public class TimCallbackHandlerFactory {

    private final Map<String, TimCallbackHandler<? extends CallbackRequest>> handlerMap = new ConcurrentHashMap<>();

    // 定义CallbackCommand与对应Request类的映射关系
    private static final Map<String, Class<? extends CallbackRequest>> REQUEST_TYPE_MAP = new ConcurrentHashMap<>();

    static {
        // 单聊消息回调
        REQUEST_TYPE_MAP.put(C2C_CALLBACK_BEFORE_SEND_MSG, BeforeSendMsgCallbackRequest.class);
        REQUEST_TYPE_MAP.put(C2C_CALLBACK_AFTER_SEND_MSG, AfterSendMsgCallbackRequest.class);
        REQUEST_TYPE_MAP.put(C2C_CALLBACK_AFTER_MSG_WITHDRAW, AfterMsgWithdrawCallbackRequest.class);
        REQUEST_TYPE_MAP.put(C2C_CALLBACK_AFTER_MSG_REPORT, AfterMsgReportCallbackRequest.class);

        // 群聊消息回调
        REQUEST_TYPE_MAP.put(GROUP_CALLBACK_BEFORE_SEND_MSG, BeforeSendGroupMsgCallbackRequest.class);
        REQUEST_TYPE_MAP.put(GROUP_CALLBACK_AFTER_SEND_MSG, AfterSendGroupMsgCallbackRequest.class);
        REQUEST_TYPE_MAP.put(GROUP_CALLBACK_AFTER_RECALL_MSG, AfterRecallGroupMsgCallbackRequest.class);
        REQUEST_TYPE_MAP.put(GROUP_CALLBACK_SEND_MSG_EXCEPTION, SendMsgExceptionCallbackRequest.class);

    }

    // 构造时自动注入所有 Handler
    public TimCallbackHandlerFactory(List<TimCallbackHandler<? extends CallbackRequest>> handlers) {
        for (TimCallbackHandler<? extends CallbackRequest> handler : handlers) {
            handlerMap.put(handler.getCommand(), handler);
        }
    }

    public TimCallbackHandler<? extends CallbackRequest> getHandler(String command) {
        return handlerMap.get(command);
    }

    public boolean supports(String command) {
        return handlerMap.containsKey(command);
    }

    /**
     * 根据CallbackCommand处理请求
     * @param callbackCommand 回调命令
     * @param requestBody 请求体JSON字符串
     * @param sdkAppid SDK应用ID
     * @param contentType 内容类型
     * @param clientIp 客户端IP
     * @param optPlatform 操作平台
     * @return 回调响应
     * @throws JsonProcessingException JSON解析异常
     */
    public CallbackResponse handle(String callbackCommand, String requestBody, String sdkAppid,
                                   String contentType, String clientIp, String optPlatform) throws JsonProcessingException {
        // 获取对应的Request类型
        Class<? extends CallbackRequest> requestClass = REQUEST_TYPE_MAP.get(callbackCommand);
        if (requestClass == null) {
            throw new IllegalArgumentException("Unsupported CallbackCommand: " + callbackCommand);
        }

        // 解析请求体
        CallbackRequest request = JsonUtils.fromJson(requestBody, requestClass);

        // 填充URL参数
        assert request != null;
        populateUrlParams(request, sdkAppid, callbackCommand, contentType, clientIp, optPlatform);

        // 获取对应的处理器
        @SuppressWarnings("unchecked")
        TimCallbackHandler<CallbackRequest> callbackHandler = (TimCallbackHandler<CallbackRequest>) getHandler(callbackCommand);
        if (callbackHandler == null) {
            throw new IllegalArgumentException("No handler found for command: " + callbackCommand);
        }

        // 处理请求并返回响应
        return callbackHandler.handle(request);
    }

    /**
     * 将从 URL 中解析的参数填充到 Request 对象中
     */
    private void populateUrlParams(CallbackRequest request, String sdkAppid, String callbackCommand,
                                   String contentType, String clientIp, String optPlatform) {
        request.setSdkAppId(Long.parseLong(sdkAppid));
        request.setCallbackCommand(callbackCommand);
        request.setContentType(contentType);
        request.setClientIp(clientIp);
        if (optPlatform != null) {
            try {
                request.setOptPlatform(optPlatform);
            } catch (NumberFormatException e) {
                log.warn("Invalid OptPlatform value: {}", optPlatform);
                request.setOptPlatform(null);
            }
        }
    }

}
